package com.leyou.order.service;

import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.clients.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.interceptors.UserInfoInterceptor;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.user.clients.UserClient;
import com.leyou.user.dto.AddressDTO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.weaver.ast.Or;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderService {

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Autowired
    private UserInfoInterceptor userInfoInterceptor;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;

    @GlobalTransactional //全局事务管理，管理了两个分支事务，（1，扣减库存分支，2下单分支）
    public Long createOrder(OrderDTO orderDTO) {


        //先减库存，减库存成功后，才能，下单，否则就是徒劳

        //把carts的list集合转换为map集合，key:skuId,value:num
        Map<Long, Integer> cartsMap = orderDTO.getCarts().stream()
                .collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));

        //请求调用item服务的减库存业务，传递的参数就是skuId以及其对应数量num组成的map集合
        this.itemClient.minusStock(cartsMap);

        //获取订单id
        long orderId = idWorker.nextId();

        //从用户信息拦截器中获取用户的登录信息
        UserInfo userInfo = userInfoInterceptor.getUserInfo();


        //跨服务根据skuId的集合查询sku的集合
        List<SkuDTO> skuDTOS = this.itemClient.querySkuByIds(new ArrayList<>(cartsMap.keySet()));

        long totalPrice = 0L;

        //当前订单下所有的订单详情
        List<OrderDetail> orderDetails = new ArrayList<>();

        for (SkuDTO skuDTO : skuDTOS) {
            Integer num = cartsMap.get(skuDTO.getId());
            //每个商品的单价*数量，累加
            totalPrice += skuDTO.getPrice() * num;

            OrderDetail orderDetail = BeanHelper.copyProperties(skuDTO, OrderDetail.class);
            orderDetail.setId(null);//这里的orderDetail的id是主键自增，如果赋值了，就不会自增，并且赋值的值，sku的id，会发生重复
            orderDetail.setOrderId(orderId);
            orderDetail.setSkuId(skuDTO.getId());
            orderDetail.setNum(num);
            orderDetail.setCreateTime(new Date());
            orderDetail.setUpdateTime(orderDetail.getCreateTime());
            //从sku的多个图片中取，逗号之前第一个
            orderDetail.setImage(StringUtils.substringBefore(skuDTO.getImages(), ","));

            orderDetails.add(orderDetail);

        }

        Order order = new Order();
        order.setOrderId(orderId);

        order.setTotalFee(totalPrice);//应该支付总价：商品的单价*数量，累加，没有单价，在sku中，拿着sku的Id去查询sku
        order.setActualFee(totalPrice);
        order.setPromotionIds(null);//优惠无
        order.setPaymentType(orderDTO.getPaymentType());//支付方式
        order.setPostFee(0L);//邮费无
        order.setUserId(userInfo.getId());//用户id
        order.setStatus(OrderStatusEnum.INIT.value());//设置订单的状态为1

        //订单保存
        int count = this.orderMapper.insertSelective(order);

        if (1 != count) {
            throw new LyException(ExceptionEnum.DATA_SAVE_ERROR);
        }


        //订单详情批量保存
        count = this.orderDetailMapper.insertList(orderDetails);

        if (count != orderDetails.size()) {
            throw new LyException(ExceptionEnum.DATA_SAVE_ERROR);
        }


        //根据用户的id以及地址的id查询用户收件地址
        AddressDTO addressDTO = this.userClient.queryAddressById(userInfo.getId(), orderDTO.getAddressId());

        //把查询到的AddressDTO转换为orderLogistics
        OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
        orderLogistics.setOrderId(orderId);

        //保存订单对应的物流收货信息
        count = this.orderLogisticsMapper.insertSelective(orderLogistics);

        if (1 != count) {
            throw new LyException(ExceptionEnum.DATA_SAVE_ERROR);
        }

        throw new RuntimeException("莫慌");

        //return orderId;


    }

    public Order queryOrderById(Long orderId) {

        Order order = this.orderMapper.selectByPrimaryKey(orderId);


        if (null == order) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }
        return order;
    }

    @Autowired
    private PayHelper payHelper;//封装

    @Autowired
    private StringRedisTemplate redisTemplate;

    public String createPayUrl(Long orderId) {

        String key = String.valueOf(orderId);

        if (redisTemplate.hasKey(key)) {//判断redis中是否有值，如果有，则返回支付链接，没有则调用微信支付
            return redisTemplate.opsForValue().get(key);
        }


        long totalPay = 1L;//实际支付的订单金额，此时在测试，所以我们不管订单多少钱，只写1，
        //TODO 在实际生产中，应该根据订单的id查询订单需要实际支付的金额

        String desc = "订单描述，应该去查询当前订单的订单详情，把买的东西列出来";
        String payUrl = this.payHelper.createOrder(orderId, totalPay, desc);


        //存储2小时
        redisTemplate.opsForValue().set(key, payUrl, 2, TimeUnit.HOURS);

        return payUrl;
    }

    public Integer queryPayState(Long orderId) {
        Order order = this.orderMapper.selectByPrimaryKey(orderId);

        if (null == order) {
            throw new LyException(ExceptionEnum.DATA_NOT_FOUND);
        }
        return order.getStatus();
    }


    @Transactional
    public void handleNotify(Map<String, String> result) {
        // 1 签名校验
        try {
            payHelper.isValidSign(result);
        } catch (Exception e) {
            log.error("【微信回调】微信签名有误！, result: {}", result, e);
            throw new LyException(ExceptionEnum.INVALID_NOTIFY_SIGN, e);
        }
        // 2、业务校验
        payHelper.checkResultCode(result);

        // 3 校验金额数据
        String totalFeeStr = result.get("total_fee");//微信实际收到的钱
        String tradeNo = result.get("out_trade_no"); //支付的订单的编号
        if (StringUtils.isEmpty(totalFeeStr) || StringUtils.isEmpty(tradeNo)) {
            // 回调参数中必须包含订单编号和订单金额
            throw new LyException(ExceptionEnum.INVALID_NOTIFY_PARAM);
        }
        // 3.1 获取结果中的金额
        long totalFee = Long.valueOf(totalFeeStr);
        // 3.2 获取订单
        Long orderId = Long.valueOf(tradeNo);
        //根据订单id查询订单信息
        Order order = orderMapper.selectByPrimaryKey(orderId);

        // 3.3.判断订单的状态，保证幂等，只要状态不是1，说明不是可支付状态，则马上收手
        if (!order.getStatus().equals(OrderStatusEnum.INIT.value())) {
            // 订单已经支付，返回成功
            return;
        }
        // 3.4.判断金额是否一致
        if (totalFee != /*order.getActualPay()*/ 1) {
            // 金额不符
            throw new LyException(ExceptionEnum.INVALID_NOTIFY_PARAM);
        }

        // 4 修改订单状态
        Order orderStatus = new Order();
        orderStatus.setStatus(OrderStatusEnum.PAY_UP.value());
        orderStatus.setOrderId(orderId);
        orderStatus.setPayTime(new Date());
        int count = orderMapper.updateByPrimaryKeySelective(orderStatus);
        if (count != 1) {
            log.error("【微信回调】更新订单状态失败，订单id：{}", orderId);
            throw new LyException(ExceptionEnum.DATA_MODIFY_ERROR);
        }
        log.info("【微信回调】, 订单支付成功! 订单编号:{}", orderId);
    }

    @Transactional
    public void cancerOrder() {

        Order record = new Order();
        record.setStatus(OrderStatusEnum.INIT.value());//查询获取未支付的订单

        //查到所有的未支付的订单
        List<Order> orderList = this.orderMapper.select(record);

        //遍历订单集合，然后找到超时的订单：当前时间-创建时间>24h

        Map<Long, Integer> skuMap = new HashMap<>();

        orderList.forEach(order -> {
            //jodaTime,创建时间+24H，如果比当前还早，则表示以及超时
            if (new DateTime(order.getCreateTime()).plusHours(24).isBeforeNow()) {

                //设置订单的状态为已关闭
                order.setStatus(OrderStatusEnum.CLOSED.value());
                //设置关闭时间
                order.setCloseTime(new Date());

                //去修改订单状态
                this.orderMapper.updateByPrimaryKeySelective(order);

                //关闭订单的同时要统计订单中的商品（查询订单详情），还原库存
                //关闭订单是批量操作，所以我们要统计每个订单中的商品，然后统一还原库存
                OrderDetail orderDetailRecord = new OrderDetail();
                orderDetailRecord.setOrderId(order.getOrderId());
                List<OrderDetail> orderDetails = this.orderDetailMapper.select(orderDetailRecord);

                //遍历当前订单的订单详情，把订单详情中对应的商品全部加入的map集合中
                orderDetails.forEach(orderDetail -> {
                    //加入时候要判断，判断之前加入过没有，如果以及加入过了，则立即马上要修改数量

                    //sku的id才表示要对这个sku进行操作
                    Long key = orderDetail.getSkuId();

                    if (skuMap.containsKey(key)) {//如果orderId存在并且是key则修改数量
                        skuMap.put(key, skuMap.get(key) + orderDetail.getNum());
                    } else {//否则直接添加
                        skuMap.put(key, orderDetail.getNum());
                    }
                });
            }
        });

        //统计出来哪些sku分别要添加多少个，则直接进行请求添加
        this.itemClient.plusStock(skuMap);


    }
}
